<?php

/**
 * This is the model class for table "user".
 *
 * The followings are the available columns in table 'user':
 * @property integer $id
 * @property string $username
 * @property string $password
 * @property string $email
 * @property string $activation_key
 *
 * The followings are the available model relations:
 * @property Bookmark[] $bookmarks
 * @property BookmarkFolder[] $bookmarkFolders
 * @property Contact[] $contacts
 * @property ContactGroup[] $contactGroups
 * @property Note[] $notes
 * @property NoteBook[] $noteBooks
 * @property Todo[] $todos
 * @property TodoList[] $todoLists
 * @property UserSession $userSession
 */
class User extends CActiveRecord {

    public $verifyCode;

    //in cases where the user changes his password
    public $oldPassword;
    public $newPassword;

    /**
     * Returns the static model of the specified AR class.
     * @return User the static model class
     */
    public static function model($className = __CLASS__) {
        return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName() {
        return 'user';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules() {
        return array(
            array('username, password, email', 'required', 'on' => 'insert'),
            array('email', 'required', 'on' => 'update'),
            array('oldPassword', 'comparePassword', 'on' => 'update'),
            array('username, password', 'length', 'min' => 6, 'max' => 32, 'on' => 'insert'),
            array('newPassword', 'length', 'min' => 6, 'max' => 32, 'on' => 'update'),
            array('email', 'email'),
            // verifyCode needs to be entered correctly
            array('verifyCode', 'captcha', 'allowEmpty' => !CCaptcha::checkRequirements(), 'on' => 'insert'),
            // check if username and email already exist
            array('username, email', 'verifyExistence', 'on' => 'insert'),
            // The following rule is used by search().
            array('username', 'safe', 'on' => 'search'),
        );
    }

    /**
     * @return array relational rules.
     */
    public function relations() {
        return array(
            'bookmarks' => array(self::HAS_MANY, 'Bookmark', 'create_user_id'),
            'bookmarkFolders' => array(self::HAS_MANY, 'BookmarkFolder', 'create_user_id'),
            'contacts' => array(self::HAS_MANY, 'Contact', 'create_user_id'),
            'contactGroups' => array(self::HAS_MANY, 'ContactGroup', 'create_user_id'),
            'notes' => array(self::HAS_MANY, 'Note', 'create_user_id'),
            'noteBooks' => array(self::HAS_MANY, 'NoteBook', 'create_user_id'),
            'todos' => array(self::HAS_MANY, 'Todo', 'create_user_id'),
            'todoLists' => array(self::HAS_MANY, 'TodoList', 'create_user_id'),
            'session' => array(self::HAS_ONE, 'UserSession', 'user_id'),
            'bookmarkCount' => array(self::STAT, 'Bookmark', 'create_user_id'),
            'folderCount' => array(self::STAT, 'BookmarkFolder', 'create_user_id'),
            'contactCount' => array(self::STAT, 'Contact', 'create_user_id'),
            'groupCount' => array(self::STAT, 'ContactGroup', 'create_user_id'),
            'noteCount' => array(self::STAT, 'Note', 'create_user_id'),
            'notebookCount' => array(self::STAT, 'NoteBook', 'create_user_id'),
            'todoCount' => array(self::STAT, 'Todo', 'create_user_id'),
            'listCount' => array(self::STAT, 'TodoList', 'create_user_id'),
        );
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels() {
        return array(
            'id' => 'ID',
            'username' => 'Username',
            'password' => 'Password',
            'email' => 'Email',
            'verifyCode' => 'Verification Code',
        );
    }

    /**
     * Check the username and email if it already exists. If true,
     * return an error to the user.
     */
    public function verifyExistence($attribute, $params) {
        if ($this->username) {
            $model = User::model()->findByAttributes(array('username' => $this->username));

            if ($model !== null)
                $this->addError('username', 'Sorry! The username you specified is already taken.');
        }
        if ($this->email) {
            $model = User::model()->findByAttributes(array('email' => $this->email));

            if ($model !== null)
                $this->addError('email', 'Sorry! The email you specified already exist.');
        }
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search() {
        $criteria = new CDbCriteria;

        $criteria->compare('username', $this->username, true);

        return new CActiveDataProvider(get_class($this), array(
            'criteria' => $criteria,
        ));
    }

    /**
     * perform one-way encryption on the password before we store it in the database
     */
    protected function beforeSave() {
        if ($this->isNewRecord)
            $this->activation_key = $this->hashPassword(uniqid('', true));

        $this->password = $this->hashPassword($this->password);

        return parent::beforeSave();
    }

    /**
     * Compare whether the oldPassword field matches the password in the database.
     * @param type $attribute
     * @param type $params
     * @return type boolean
     */
    public function comparePassword($attribute, $params) {
        if ($this->oldPassword) {
            $user = User::model()->findByPk(Yii::app()->user->id);

            if (!$user->checkPassword($this->oldPassword))
                $this->addError('oldPassword', 'Old Password field does not match your current password.');
        }
    }

    /**
     * Generates the password hash.
     * @param string password
     * @return string hash
     */
    public function hashPassword($password) {
        $passwordHash = new PasswordHash(8, false);
        return $passwordHash->HashPassword($password);
    }

    /**
     * Checks if the given password is correct.
     * @param string the password to be validated
     * @return boolean whether the password is valid
     */
    public function checkPassword($password) {
        $passwordHash = new PasswordHash(8, false);
        return $passwordHash->checkPassword($password, $this->password);
    }

}